From 613213f597462f93767f85ffbc33eb522d7e3090 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 30 Jun 2020 14:50:01 -0400 Subject: [PATCH] inspector: proper list model support Add a data tab for list models that allows exploring the objects in the model. --- gtk/inspector/init.c | 2 + gtk/inspector/list-data.c | 274 +++++++++++++++++++++++++++++++++++++ gtk/inspector/list-data.h | 38 +++++ gtk/inspector/list-data.ui | 68 +++++++++ gtk/inspector/meson.build | 1 + gtk/inspector/window.c | 3 + gtk/inspector/window.h | 1 + gtk/inspector/window.ui | 11 ++ 8 files changed, 398 insertions(+) create mode 100644 gtk/inspector/list-data.c create mode 100644 gtk/inspector/list-data.h create mode 100644 gtk/inspector/list-data.ui diff --git a/gtk/inspector/init.c b/gtk/inspector/init.c index 59d09e30c9..fad5f9b5b7 100644 --- a/gtk/inspector/init.c +++ b/gtk/inspector/init.c @@ -31,6 +31,7 @@ #include "css-node-tree.h" #include "general.h" #include "graphdata.h" +#include "list-data.h" #include "logs.h" #include "magnifier.h" #include "menu.h" @@ -65,6 +66,7 @@ gtk_inspector_init (void) g_type_ensure (GTK_TYPE_INSPECTOR_CSS_EDITOR); g_type_ensure (GTK_TYPE_INSPECTOR_CSS_NODE_TREE); g_type_ensure (GTK_TYPE_INSPECTOR_GENERAL); + g_type_ensure (GTK_TYPE_INSPECTOR_LIST_DATA); g_type_ensure (GTK_TYPE_INSPECTOR_LOGS); g_type_ensure (GTK_TYPE_MAGNIFIER); g_type_ensure (GTK_TYPE_INSPECTOR_MAGNIFIER); diff --git a/gtk/inspector/list-data.c b/gtk/inspector/list-data.c new file mode 100644 index 0000000000..bfa0b7f9a1 --- /dev/null +++ b/gtk/inspector/list-data.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2020 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" +#include + +#include "list-data.h" + +#include "object-tree.h" + +#include "gtkcolumnview.h" +#include "gtktogglebutton.h" +#include "gtklabel.h" +#include "gtkstack.h" +#include "gtkboxlayout.h" +#include "gtkorientable.h" +#include "gtknoselection.h" +#include "gtksignallistitemfactory.h" +#include "gtklistitem.h" + + +struct _GtkInspectorListData +{ + GtkWidget parent_instance; + + GtkInspectorObjectTree *object_tree; + GListModel *object; + GtkColumnView *view; + GtkWidget *items_label; +}; + +struct _GtkInspectorListDataClass +{ + GtkWidgetClass parent_class; +}; + +enum +{ + PROP_0, + PROP_OBJECT_TREE, +}; + +G_DEFINE_TYPE (GtkInspectorListData, gtk_inspector_list_data, GTK_TYPE_WIDGET) + +static void +gtk_inspector_list_data_init (GtkInspectorListData *sl) +{ + gtk_widget_init_template (GTK_WIDGET (sl)); + + gtk_orientable_set_orientation (GTK_ORIENTABLE (gtk_widget_get_layout_manager (GTK_WIDGET (sl))), + GTK_ORIENTATION_VERTICAL); +} + +void +gtk_inspector_list_data_set_object (GtkInspectorListData *sl, + GObject *object) +{ + GtkWidget *stack; + GtkStackPage *page; + char *text; + GtkNoSelection *selection; + + stack = gtk_widget_get_parent (GTK_WIDGET (sl)); + page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl)); + + gtk_column_view_set_model (sl->view, NULL); + sl->object = NULL; + + if (!G_IS_LIST_MODEL (object)) + { + g_object_set (page, "visible", FALSE, NULL); + return; + } + + text = g_strdup_printf ("%u items", g_list_model_get_n_items (G_LIST_MODEL (object))); + gtk_label_set_label (GTK_LABEL (sl->items_label), text); + g_free (text); + + g_object_set (page, "visible", TRUE, NULL); + + sl->object = G_LIST_MODEL (object); + selection = gtk_no_selection_new (sl->object); + gtk_column_view_set_model (sl->view, G_LIST_MODEL (selection)); + g_object_unref (selection); +} + +static void +setup_object (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + GtkWidget *label; + + label = gtk_label_new (""); + gtk_label_set_xalign (GTK_LABEL (label), 0); + gtk_widget_add_css_class (label, "cell"); + gtk_list_item_set_child (item, label); +} + +static void +bind_object (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + GtkWidget *label; + gpointer obj; + char *text; + + label = gtk_list_item_get_child (item); + obj = gtk_list_item_get_item (item); + + text = g_strdup_printf ("%p", obj); + gtk_label_set_label (GTK_LABEL (label), text); + g_free (text); +} + +static void +setup_type (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + GtkWidget *label; + + label = gtk_label_new (""); + gtk_label_set_xalign (GTK_LABEL (label), 0); + gtk_widget_add_css_class (label, "cell"); + gtk_list_item_set_child (item, label); +} + +static void +bind_type (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + GtkWidget *label; + gpointer obj; + + label = gtk_list_item_get_child (item); + obj = gtk_list_item_get_item (item); + + gtk_label_set_label (GTK_LABEL (label), G_OBJECT_TYPE_NAME (obj)); +} + +static void +setup_props (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + GtkWidget *button; + + button = gtk_button_new_with_label ("Properties"); + gtk_widget_add_css_class (button, "cell"); + gtk_widget_set_halign (button, GTK_ALIGN_START); + gtk_list_item_set_child (item, button); +} + +static void +object_properties (GtkWidget *button, + GtkListItem *item) +{ + GtkInspectorListData *sl; + gpointer obj; + + sl = GTK_INSPECTOR_LIST_DATA (gtk_widget_get_ancestor (button, GTK_TYPE_INSPECTOR_LIST_DATA)); + obj = gtk_list_item_get_item (item); + g_object_set_data (G_OBJECT (sl->object_tree), "next-tab", (gpointer)"properties"); + gtk_inspector_object_tree_activate_object (sl->object_tree, obj); +} + +static void +bind_props (GtkSignalListItemFactory *factory, + GtkListItem *item, + GtkInspectorListData *sl) +{ + g_signal_connect (gtk_list_item_get_child (item), "clicked", + G_CALLBACK (object_properties), item); +} + +static void +unbind_props (GtkSignalListItemFactory *factory, + GtkListItem *item) +{ + g_signal_handlers_disconnect_by_func (gtk_list_item_get_child (item), object_properties, item); +} + +static void +get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GtkInspectorListData *sl = GTK_INSPECTOR_LIST_DATA (object); + + switch (param_id) + { + case PROP_OBJECT_TREE: + g_value_take_object (value, sl->object_tree); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkInspectorListData *sl = GTK_INSPECTOR_LIST_DATA (object); + + switch (param_id) + { + case PROP_OBJECT_TREE: + sl->object_tree = g_value_get_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +finalize (GObject *object) +{ + GtkInspectorListData *sl = GTK_INSPECTOR_LIST_DATA (object); + + gtk_inspector_list_data_set_object (sl, NULL); + + G_OBJECT_CLASS (gtk_inspector_list_data_parent_class)->finalize (object); +} + +static void +gtk_inspector_list_data_class_init (GtkInspectorListDataClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; + + g_object_class_install_property (object_class, PROP_OBJECT_TREE, + g_param_spec_object ("object-tree", "Object Tree", "Object tree", + GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/list-data.ui"); + gtk_widget_class_bind_template_child (widget_class, GtkInspectorListData, view); + gtk_widget_class_bind_template_child (widget_class, GtkInspectorListData, items_label); + + gtk_widget_class_bind_template_callback (widget_class, setup_object); + gtk_widget_class_bind_template_callback (widget_class, bind_object); + gtk_widget_class_bind_template_callback (widget_class, setup_type); + gtk_widget_class_bind_template_callback (widget_class, bind_type); + gtk_widget_class_bind_template_callback (widget_class, setup_props); + gtk_widget_class_bind_template_callback (widget_class, bind_props); + gtk_widget_class_bind_template_callback (widget_class, unbind_props); + + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT); +} + +// vim: set et sw=2 ts=2: diff --git a/gtk/inspector/list-data.h b/gtk/inspector/list-data.h new file mode 100644 index 0000000000..a0a98d41c9 --- /dev/null +++ b/gtk/inspector/list-data.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#ifndef _GTK_INSPECTOR_LIST_DATA_H_ +#define _GTK_INSPECTOR_LIST_DATA_H_ + +#include + +#define GTK_TYPE_INSPECTOR_LIST_DATA (gtk_inspector_list_data_get_type()) + +G_DECLARE_FINAL_TYPE (GtkInspectorListData, gtk_inspector_list_data, GTK, INSPECTOR_LIST_DATA, GtkWidget) + +typedef struct _GtkInspectorListData GtkInspectorListData; + +G_BEGIN_DECLS + +void gtk_inspector_list_data_set_object (GtkInspectorListData *sl, + GObject *object); + +G_END_DECLS + +#endif // _GTK_INSPECTOR_LIST_DATA_H_ + +// vim: set et sw=2 ts=2: diff --git a/gtk/inspector/list-data.ui b/gtk/inspector/list-data.ui new file mode 100644 index 0000000000..d3124ed548 --- /dev/null +++ b/gtk/inspector/list-data.ui @@ -0,0 +1,68 @@ + + + diff --git a/gtk/inspector/meson.build b/gtk/inspector/meson.build index b2d00b74c5..90370de758 100644 --- a/gtk/inspector/meson.build +++ b/gtk/inspector/meson.build @@ -15,6 +15,7 @@ inspector_sources = files( 'init.c', 'inspect-button.c', 'inspectoroverlay.c', + 'list-data.c', 'layoutoverlay.c', 'logs.c', 'magnifier.c', diff --git a/gtk/inspector/window.c b/gtk/inspector/window.c index 626e3163a8..a69daa30e6 100644 --- a/gtk/inspector/window.c +++ b/gtk/inspector/window.c @@ -37,6 +37,7 @@ #include "size-groups.h" #include "actions.h" #include "shortcuts.h" +#include "list-data.h" #include "menu.h" #include "misc-info.h" #include "magnifier.h" @@ -101,6 +102,7 @@ set_selected_object (GtkInspectorWindow *iw, gtk_inspector_css_node_tree_set_object (GTK_INSPECTOR_CSS_NODE_TREE (iw->widget_css_node_tree), selected); gtk_inspector_size_groups_set_object (GTK_INSPECTOR_SIZE_GROUPS (iw->size_groups), selected); gtk_inspector_tree_data_set_object (GTK_INSPECTOR_TREE_DATA (iw->tree_data), selected); + gtk_inspector_list_data_set_object (GTK_INSPECTOR_LIST_DATA (iw->list_data), selected); gtk_inspector_actions_set_object (GTK_INSPECTOR_ACTIONS (iw->actions), selected); gtk_inspector_shortcuts_set_object (GTK_INSPECTOR_SHORTCUTS (iw->shortcuts), selected); gtk_inspector_menu_set_object (GTK_INSPECTOR_MENU (iw->menu), selected); @@ -446,6 +448,7 @@ gtk_inspector_window_class_init (GtkInspectorWindowClass *klass) gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, object_title); gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, size_groups); gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, tree_data); + gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, list_data); gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, actions); gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, shortcuts); gtk_widget_class_bind_template_child (widget_class, GtkInspectorWindow, menu); diff --git a/gtk/inspector/window.h b/gtk/inspector/window.h index fe2dd5a03d..fe5f9f7d29 100644 --- a/gtk/inspector/window.h +++ b/gtk/inspector/window.h @@ -65,6 +65,7 @@ typedef struct GtkWidget *object_hierarchy; GtkWidget *size_groups; GtkWidget *tree_data; + GtkWidget *list_data; GtkWidget *actions; GtkWidget *shortcuts; GtkWidget *menu; diff --git a/gtk/inspector/window.ui b/gtk/inspector/window.ui index cfddd20fdc..55a5569209 100644 --- a/gtk/inspector/window.ui +++ b/gtk/inspector/window.ui @@ -409,6 +409,17 @@ + + + list-data + Data + + + object_tree + + + + actions -- 2.30.2